Windows内核逆向——<中断处理 从硬件机制到用户驱动接管>
看雪论坛作者ID:小白养的菜鸡
CPU相关知识:
APIC(Advanced Programmable Interrupt Controller)
配置 local APIC
(1)通过 写IA32_APIC_BASE MSR寄存器,将其寄存器空间映射至内存,访问内存,进行配置。
(2)通过读写MSR寄存器的方式对APIC提供的功能进行配置(所有配置均通过写MSR寄存器完成配置)。
优先级机制(Task and Processor Priorities)
PPR(Processor-Priority Register)为只读寄存器 PPR[7:4] 等价于TPR[7:4] ,在local APIC中将中断发送给处理器前会通过读此寄存器的值决定是否打断处理器的执行流(投递中断),这也是系统在高IRQL不会被第IRQL中断的原因。
IDT 表 由硬件到软件:
(为了叙述简单忽略由IST 位引起的自动栈切换)
(1)IDTR 寄存器
(2)LIDT 指令
(3)中断描述符
每个可用的中断号对应一个,由操作系统构造并写入IDT表中说明了,一个由local APIC 投递的中断,被CPU收到时,应该跳转到的中断处理程序的位置,以及栈的位置。
(4)中断向量号的分配
0-21 号中断 :用于对CPU中产生的异常的处理
22-31 号中断 :被intel保留,无法被使用
31-255 号中断 :由系统自行分配
(5)如何根据一个中断向量号找到一个中断描述符的细节
(6)中断后的栈
(7)软件接管
根据上文所述目前的中断处理流程为:
I/O APIC -> Local APIC -> IDT -> 系统的中断处理例程
(1)收到中断后的处理流程
(2)驱动程序注册ISR(Interrupt Service Routines)的过程
收到中断后的处理流程
可以明显看出:
0-0x15(21)号中断 :用于对CPU中产生的异常的处理
22-31(1f) 号中断 :未被使用
31-255 号中断 :由系统自行分配
以0x35号向量为例开始分析 使用 u ffff803801dee38 指令对IDT描述符所指中断处理例程进行反汇编,发现其存在明显特征 即在栈中压入其中断向量号0x35 和 rbp 寄存器地址后,进行跳转且 下文存在同样结构,在压入0x36和rbp后进行跳转,且跳转地址一致,我们猜测0x36号中断的中断处理例程指向push 0x36 首地址,通过分析证明此猜测正确。
在IDA中加载内核文件,并重定位基址使其于windbg中一致,发现大量一致性结构 ,证明 对所有中断处理的第一步 是首先执行 KiIsrThunkShadow 中对应的代码,用于在栈中压入对应的中断向量,和保存rbp。
开启页表隔离后应为,可以看出少压入了rbp。
少压入的rbp参数会在进入KiIsrLinkage 前被补充,所以页表隔离并不影响中断处理的主要逻辑。
分析KxIsrLinkageShadow函数(开启页表隔离的情况下的中断处理流程)
分析KxIsrLinkage的主要部分
_guard_dispatch_icall 函数用作指令流保护,意在利用编译时产生的cfgbitmap,检测出 被跳转位置是否为合法地址,已阻止 shellocde 的执行此处等价于 jmp rax。
① 在栈中压入中断号
② 处理页表隔离
③ 保存好中断前的线程上下文
④ 根据中断向量号 在此核心的KPCR中找到对应的中断对象
⑤ 调用中断对象的 DispatchAddress函数
下文开始分析驱动程序注册ISR(Interrupt Service Routines)的过程。
The IoConnectInterrupt routine registers a device driver's InterruptService routine (ISR), so that it will be called when a device interrupts on any of a specified set of processors.
NTSTATUS IoConnectInterrupt(
[out] PKINTERRUPT *InterruptObject,
[in] PKSERVICE_ROUTINE ServiceRoutine,
[in, optional] PVOID ServiceContext,
[in, optional] PKSPIN_LOCK SpinLock,
[in] ULONG Vector,
[in] KIRQL Irql,
[in] KIRQL SynchronizeIrql,
[in] KINTERRUPT_MODE InterruptMode,
[in] BOOLEAN ShareVector,
[in] KAFFINITY ProcessorEnableMask,
[in] BOOLEAN FloatingSave
);
[out] InterruptObject 输出参数,返回被初始化好的中断对象
[in] ServiceRoutine 由用户驱动实现的中断响应函数
[in, optional] ServiceContext 调用用户中断响应函数时传递的参数
[in] Vector 中断响应函数对应的中断向量
KeInitializeInterruptEx 用于初始化一个中断对象:
IoConnectInterruptEx -> IopConnectInterrupt -> KeConnectInterrupt—>KiConnectInterrupt
由此得出_KINTERRUPT.DispatchAddress = KiChainedDispatch
KiChainedDispatch->KiScanInterruptObjectList
->KiCallInterruptServiceRoutine
KiCallInterruptServiceRoutine 调用由用户注册的ISR函数
从一个中断到达I/O APIC 至用户注册的ISR被调用的过程:
1)I/O APIC
2)local APIC
3)IDT
3)KiIsrThunkShadow
4)KxIsrLinkageShadow
5)KiChainedDispatch
6)KiCallInterruptServiceRoutine
7)_KINTERRUPT.ServiceRoutine
看雪ID:小白养的菜鸡
https://bbs.pediy.com/user-home-882390.htm
# 往期推荐
1.Chrome v8 issue 1234770(CVE-2021-30599)漏洞分析
球分享
球点赞
球在看
点击“阅读原文”,了解更多!